package com.weishu.upf.service_management.app; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.IBinder; import android.util.Log; import com.weishu.upf.service_management.app.hook.AMSHookHelper; /** * @author weishu * @date 16/5/10 */ public final class ServiceManager { private static final String TAG = "ServiceManager"; private static volatile ServiceManager sInstance; private Map<String, Service> mServiceMap = new HashMap<String, Service>(); // 存储插件的Service信息 private Map<ComponentName, ServiceInfo> mServiceInfoMap = new HashMap<ComponentName, ServiceInfo>(); public synchronized static ServiceManager getInstance() { if (sInstance == null) { sInstance = new ServiceManager(); } return sInstance; } /** * 启动某个插件Service; 如果Service还没有启动, 那么会创建新的插件Service * @param proxyIntent * @param startId */ public void onStart(Intent proxyIntent, int startId) { Intent targetIntent = proxyIntent.getParcelableExtra(AMSHookHelper.EXTRA_TARGET_INTENT); ServiceInfo serviceInfo = selectPluginService(targetIntent); if (serviceInfo == null) { Log.w(TAG, "can not found service : " + targetIntent.getComponent()); return; } try { if (!mServiceMap.containsKey(serviceInfo.name)) { // service还不存在, 先创建 proxyCreateService(serviceInfo); } Service service = mServiceMap.get(serviceInfo.name); service.onStart(targetIntent, startId); } catch (Exception e) { e.printStackTrace(); } } /** * 停止某个插件Service, 当全部的插件Service都停止之后, ProxyService也会停止 * @param targetIntent * @return */ public int stopService(Intent targetIntent) { ServiceInfo serviceInfo = selectPluginService(targetIntent); if (serviceInfo == null) { Log.w(TAG, "can not found service: " + targetIntent.getComponent()); return 0; } Service service = mServiceMap.get(serviceInfo.name); if (service == null) { Log.w(TAG, "can not runnning, are you stopped it multi-times?"); return 0; } service.onDestroy(); mServiceMap.remove(serviceInfo.name); if (mServiceMap.isEmpty()) { // 没有Service了, 这个没有必要存在了 Log.d(TAG, "service all stopped, stop proxy"); Context appContext = UPFApplication.getContext(); appContext.stopService(new Intent().setComponent(new ComponentName(appContext.getPackageName(), ProxyService.class.getName()))); } return 1; } /** * 选择匹配的ServiceInfo * @param pluginIntent 插件的Intent * @return */ private ServiceInfo selectPluginService(Intent pluginIntent) { for (ComponentName componentName : mServiceInfoMap.keySet()) { if (componentName.equals(pluginIntent.getComponent())) { return mServiceInfoMap.get(componentName); } } return null; } /** * 通过ActivityThread的handleCreateService方法创建出Service对象 * @param serviceInfo 插件的ServiceInfo * @throws Exception */ private void proxyCreateService(ServiceInfo serviceInfo) throws Exception { IBinder token = new Binder(); // 创建CreateServiceData对象, 用来传递给ActivityThread的handleCreateService 当作参数 Class<?> createServiceDataClass = Class.forName("android.app.ActivityThread$CreateServiceData"); Constructor<?> constructor = createServiceDataClass.getDeclaredConstructor(); constructor.setAccessible(true); Object createServiceData = constructor.newInstance(); // 写入我们创建的createServiceData的token字段, ActivityThread的handleCreateService用这个作为key存储Service Field tokenField = createServiceDataClass.getDeclaredField("token"); tokenField.setAccessible(true); tokenField.set(createServiceData, token); // 写入info对象 // 这个修改是为了loadClass的时候, LoadedApk会是主程序的ClassLoader, 我们选择Hook BaseDexClassLoader的方式加载插件 serviceInfo.applicationInfo.packageName = UPFApplication.getContext().getPackageName(); Field infoField = createServiceDataClass.getDeclaredField("info"); infoField.setAccessible(true); infoField.set(createServiceData, serviceInfo); // 写入compatInfo字段 // 获取默认的compatibility配置 Class<?> compatibilityClass = Class.forName("android.content.res.CompatibilityInfo"); Field defaultCompatibilityField = compatibilityClass.getDeclaredField("DEFAULT_COMPATIBILITY_INFO"); Object defaultCompatibility = defaultCompatibilityField.get(null); Field compatInfoField = createServiceDataClass.getDeclaredField("compatInfo"); compatInfoField.setAccessible(true); compatInfoField.set(createServiceData, defaultCompatibility); Class<?> activityThreadClass = Class.forName("android.app.ActivityThread"); Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread"); Object currentActivityThread = currentActivityThreadMethod.invoke(null); // private void handleCreateService(CreateServiceData data) { Method handleCreateServiceMethod = activityThreadClass.getDeclaredMethod("handleCreateService", createServiceDataClass); handleCreateServiceMethod.setAccessible(true); handleCreateServiceMethod.invoke(currentActivityThread, createServiceData); // handleCreateService创建出来的Service对象并没有返回, 而是存储在ActivityThread的mServices字段里面, 这里我们手动把它取出来 Field mServicesField = activityThreadClass.getDeclaredField("mServices"); mServicesField.setAccessible(true); Map mServices = (Map) mServicesField.get(currentActivityThread); Service service = (Service) mServices.get(token); // 获取到之后, 移除这个service, 我们只是借花献佛 mServices.remove(token); // 将此Service存储起来 mServiceMap.put(serviceInfo.name, service); } /** * 解析Apk文件中的 <service>, 并存储起来 * 主要是调用PackageParser类的generateServiceInfo方法 * @param apkFile 插件对应的apk文件 * @throws Exception 解析出错或者反射调用出错, 均会抛出异常 */ public void preLoadServices(File apkFile) throws Exception { Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser"); Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class); Object packageParser = packageParserClass.newInstance(); // 首先调用parsePackage获取到apk对象对应的Package对象 Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_SERVICES); // 读取Package对象里面的services字段 // 接下来要做的就是根据这个List<Service> 获取到Service对应的ServiceInfo Field servicesField = packageObj.getClass().getDeclaredField("services"); List services = (List) servicesField.get(packageObj); // 调用generateServiceInfo 方法, 把PackageParser.Service转换成ServiceInfo Class<?> packageParser$ServiceClass = Class.forName("android.content.pm.PackageParser$Service"); Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState"); Class<?> userHandler = Class.forName("android.os.UserHandle"); Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId"); int userId = (Integer) getCallingUserIdMethod.invoke(null); Object defaultUserState = packageUserStateClass.newInstance(); // 需要调用 android.content.pm.PackageParser#generateActivityInfo(android.content.pm.ActivityInfo, int, android.content.pm.PackageUserState, int) Method generateReceiverInfo = packageParserClass.getDeclaredMethod("generateServiceInfo", packageParser$ServiceClass, int.class, packageUserStateClass, int.class); // 解析出intent对应的Service组件 for (Object service : services) { ServiceInfo info = (ServiceInfo) generateReceiverInfo.invoke(packageParser, service, 0, defaultUserState, userId); mServiceInfoMap.put(new ComponentName(info.packageName, info.name), info); } } }